package com.lineage.server.timecontroller.pc;

import com.lineage.server.datatables.MapHprMprRangeTable;
import com.lineage.server.datatables.MapHprMprTable;
import com.lineage.server.model.Instance.L1EffectInstance;
import com.lineage.server.model.Instance.L1PcInstance;
import com.lineage.server.model.L1HouseLocation;
import com.lineage.server.model.L1Object;
import com.lineage.server.types.Point;
import java.util.ConcurrentModificationException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Random;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class HprExecutor {
  private static final Log _log = LogFactory.getLog(HprExecutor.class);
  
  private static final Map<Integer, Integer> _skill = new HashMap<>();
  
  private static final Map<Integer, Integer> _mapIdU = new HashMap<>();
  
  private static final Map<Integer, Integer> _mapIdD = new HashMap<>();
  
  private static HprExecutor _instance;
  
  private HprExecutor() {
    _skill.put(Integer.valueOf(158), Integer.valueOf(15));
    _skill.put(Integer.valueOf(3005), Integer.valueOf(3));
    _skill.put(Integer.valueOf(3013), Integer.valueOf(3));
    _skill.put(Integer.valueOf(3020), Integer.valueOf(2));
    _skill.put(Integer.valueOf(3028), Integer.valueOf(2));
    _skill.put(Integer.valueOf(3038), Integer.valueOf(2));
    _skill.put(Integer.valueOf(3046), Integer.valueOf(2));
    _mapIdD.put(Integer.valueOf(410), Integer.valueOf(-10));
    _mapIdD.put(Integer.valueOf(2000), Integer.valueOf(-10));
    _mapIdD.put(Integer.valueOf(306), Integer.valueOf(-10));
  }
  
  protected static HprExecutor get() {
    if (_instance == null)
      _instance = new HprExecutor(); 
    return _instance;
  }
  
  private static void regenHp(L1PcInstance tgpc) {
    tgpc.set_hpRegenType(0);
    int maxBonus = 1;
    if (tgpc.getLevel() > 11 && tgpc.getCon() >= 14)
      maxBonus = Math.min(tgpc.getCon() - 12, 14); 
    int equipHpr = tgpc.getInventory().hpRegenPerTick();
    equipHpr += tgpc.getHpr();
    Random random = new Random();
    int bonus = random.nextInt(maxBonus) + 1;
    if (!tgpc.getSkillisEmpty() && tgpc.getSkillEffect().size() > 0)
      try {
        Iterator<Integer> iterator = _skill.keySet().iterator();
        while (iterator.hasNext()) {
          Integer skillid = iterator.next();
          if (tgpc.hasSkillEffect(skillid.intValue())) {
            Integer integer = _skill.get(skillid);
            if (integer == null)
              continue; 
            bonus += integer.intValue();
          } 
        } 
      } catch (ConcurrentModificationException concurrentModificationException) {
      
      } catch (Exception e) {
        _log.error(e.getLocalizedMessage(), e);
      }  
    short mapid = tgpc.getMapId();
    int maphp = MapHprMprTable.get().getMapHpr(tgpc, mapid);
    int maphp2 = MapHprMprTable.get().getMapHpr(tgpc, 32767);
    int maphp3 = MapHprMprRangeTable.get().getMapHpr(tgpc, mapid);
    if (maphp != 0)
      bonus += maphp; 
    if (L1HouseLocation.isInHouse(tgpc.getX(), tgpc.getY(), tgpc.getMapId()))
      bonus += maphp2; 
    if (maphp3 != 0)
      bonus += maphp3; 
    Integer rhp = _mapIdU.get(new Integer(tgpc.getMapId()));
    if (rhp != null)
      bonus += rhp.intValue(); 
    if (tgpc.isElf() && tgpc.getMapId() == 4 && tgpc.getLocation().isInScreen(new Point(33055, 32336)))
      bonus += 5; 
    if (tgpc.getOriginalHpr() > 0)
      bonus += tgpc.getOriginalHpr(); 
    boolean inLifeStream = false;
    if (isPlayerInLifeStream(tgpc)) {
      inLifeStream = true;
      bonus += 3;
    } 
    int newHp = tgpc.getCurrentHp();
    newHp += bonus + equipHpr;
    newHp = Math.max(newHp, 1);
    if (isUnderwater(tgpc))
      newHp -= 20; 
    Integer dhp = _mapIdD.get(new Integer(tgpc.getMapId()));
    if (dhp != null && !inLifeStream)
      bonus += dhp.intValue(); 
    newHp = Math.max(newHp, 0);
    tgpc.setCurrentHp(newHp);
  }
  
  private static boolean isUnderwater(L1PcInstance pc) {
    return (!pc.getInventory().checkEquipped(20207) && 
      !pc.hasSkillEffect(1003) && (!pc.getInventory().checkEquipped(21048) || 
      !pc.getInventory().checkEquipped(21049) || !pc.getInventory().checkEquipped(21050)) && 
      pc.getMap().isUnderwater());
  }
  
  private static boolean isPlayerInLifeStream(L1PcInstance pc) {
    Iterator<L1Object> iterator = pc.getKnownObjects().iterator();
    while (iterator.hasNext()) {
      L1Object object = iterator.next();
      if (object instanceof L1EffectInstance) {
        L1EffectInstance effect = (L1EffectInstance)object;
        if (effect.getNpcId() == 81169 && effect.getLocation().getTileLineDistance((Point)pc.getLocation()) < 4)
          return true; 
      } 
    } 
    return false;
  }
  
  protected boolean check(L1PcInstance tgpc) {
    try {
      if (tgpc == null)
        return false; 
      if (tgpc.getOnlineStatus() == 0)
        return false; 
      if (tgpc.getNetConnection() == null)
        return false; 
      if (tgpc.isDead())
        return false; 
      if (tgpc.isTeleport())
        return false; 
      Integer dhp = _mapIdD.get(new Integer(tgpc.getMapId()));
      if (dhp != null)
        return true; 
      if (isUnderwater(tgpc))
        return true; 
      if (tgpc.getCurrentHp() >= tgpc.getMaxHp())
        return false; 
    } catch (Exception e) {
      _log.error(e.getLocalizedMessage(), e);
      return false;
    } 
    return true;
  }
  
  protected void checkRegenHp(L1PcInstance tgpc) {
    try {
      tgpc.set_hpRegenType(tgpc.hpRegenType() + tgpc.getHpRegenState());
      tgpc.setRegenState(4);
      if (tgpc.isRegenHp())
        regenHp(tgpc); 
    } catch (Exception e) {
      _log.error(e.getLocalizedMessage(), e);
    } 
  }
}
